/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2019 Intel Corporation.
 */

#include "pg_strings.h"

#define SIZE_OF_PORTLIST      (sizeof(portlist_t) * 8)

char *
pg_strtrim(char *str)
{
	if (!str || !*str)
		return str;

	/* trim white space characters at the front */
	while(isspace(*str))
		str++;

	/* Make sure the string is not empty */
	if (*str) {
		char *p = &str[strlen(str) - 1];

		/* trim trailing white space characters */
		while((p >= str) && isspace(*p))
			p--;

		p[1] = '\0';
	}
	return str;
}

int
pg_strtok(char *str, const char *delim, char **entries, int maxtokens)
{
	int i = 0;
	char *saved;

	if (!str || !delim || !entries || !maxtokens)
		return -1;

	do {
		entries[i] = pg_strtrim(strtok_r(str, delim, &saved));
		str = NULL;
	} while(entries[i] && (++i < maxtokens));

	return i;
}

int
pg_strqtok(char *str, const char *delim, char *argv[], int maxtokens)
{
	char *p, *start_of_word, *s;
	int argc = 0;
	enum { INIT, WORD, STRING_QUOTE, STRING_TICK, STRING_BRACKET } state = WORD;

	if (!str || !delim || !argv || maxtokens == 0)
		return -1;

	/* Remove white space from start and end of string */
	s = pg_strtrim(str);

	start_of_word = s;
	for (p = s; (argc < maxtokens) && (*p != '\0'); p++) {
		int c = (unsigned char)*p;

		if (c == '\\') {
			start_of_word = ++p;
			continue;
		}

		switch (state) {
		case INIT:
			if (c == '"') {
				state = STRING_QUOTE;
				start_of_word = p + 1;
			} else if (c == '\'') {
				state = STRING_TICK;
				start_of_word = p + 1;
			} else if (c == '{') {
				state = STRING_BRACKET;
				start_of_word = p + 1;
			} else if (!strchr(delim, c)) {
				state = WORD;
				start_of_word = p;
			}
			break;

		case STRING_QUOTE:
			if (c == '"') {
				*p = 0;
				argv[argc++] = start_of_word;
				state = INIT;
			}
			break;

		case STRING_TICK:
			if (c == '\'') {
				*p = 0;
				argv[argc++] = start_of_word;
				state = INIT;
			}
			break;

		case STRING_BRACKET:
			if (c == '}') {
				*p = 0;
				argv[argc++] = start_of_word;
				state = INIT;
			}
			break;

		case WORD:
			if (strchr(delim, c)) {
				*p = 0;
				argv[argc++] = start_of_word;
				state = INIT;
				start_of_word = p + 1;
			}
			break;

		default:
			break;
		}
	}

	if ((state != INIT) && (argc < maxtokens))
		argv[argc++] = start_of_word;

	if ((argc == 0) && (p != str))
		argv[argc++] = str;

	return argc;
}

int
pg_stropt(const char *list, char *str, const char *delim)
{
	char *argv[STR_MAX_ARGVS + 1], *buf;
	size_t n, i;

	if (!list || !str || !delim)
		return -1;

	if ((list[0] == '%') && (list[1] == '|'))
		list += 2;

	if (!*list)
		return -1;

	n = strlen(list) + 2;

	buf = alloca(n);
	if (buf) {
		snprintf(buf, n, "%s", list);

		n = pg_strtok(buf, delim, argv, STR_MAX_ARGVS);

		for (i = 0; i < n; i++)
			if (pg_strmatch(argv[i], str))
				return i;
	}

	return -1;
}

int
pg_parse_corelist(const char *corelist, uint8_t *lcores, int len)
{
	int idx = 0;
	unsigned count = 0;
	char *end = NULL;
	int min, max, k;
	char cl_buf[128], *cl = cl_buf;

	if (corelist == NULL)
		return -1;

	memset(lcores, 0, len);

	strlcpy(cl, corelist, sizeof(cl_buf));

	/* Remove all blank characters ahead and after */
	cl = pg_strtrim(cl);

	/* Get list of cores */
	min = RTE_MAX_LCORE;
	k = 0;
	do {
		while (isblank(*cl))
			cl++;

		if (*cl == '\0')
			return -1;

		errno = 0;
		idx = strtoul(cl, &end, 10);
		if (errno || end == NULL)
			return -1;

		while (isblank(*end))
			end++;

		if (*end == '-')
			min = idx;
		else if ((*end == ',') || (*end == '\0')) {
			max = idx;

			if (min == RTE_MAX_LCORE)
				min = idx;

			for (idx = min; idx <= max; idx++) {
				lcores[idx] = 1;
				count++;
			}

			min = RTE_MAX_LCORE;
		} else
			return -1;

		cl = end + 1;

		if (k >= len)
			return -1;
	} while (*end != '\0');

	return count;
}
